package rad.framework.jndi;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;

import org.apache.commons.logging.Log;

public class JndiUtil {

	private static InitialContext initialContext;

	public static InitialContext getInitialContext() {
		if (initialContext == null) {
			try {
				initialContext = new InitialContext();
			} catch (NamingException e) {
				throw new RuntimeException(e);
			}
		}
		return initialContext;
	}

	public static Object lookup(String beanName) {
		try {
			return getInitialContext().lookup(beanName);
		} catch (NamingException ex) {
			throw new RuntimeException("Couldn't lookup: " + beanName, ex);
		}
	}

	public static Object lookup(String beanName, String user, String password) {
		InitialContext ctx = null;
		try {
			Properties env = new Properties();
			env.setProperty(Context.SECURITY_PRINCIPAL, user);
			env.setProperty(Context.SECURITY_CREDENTIALS, password);
			env.setProperty(Context.INITIAL_CONTEXT_FACTORY,
					"org.jboss.security.jndi.JndiLoginInitialContextFactory");
			ctx = new InitialContext(env);

			return ctx.lookup(beanName);
		} catch (NamingException ex) {
			throw new RuntimeException("Couldn't lookup: " + beanName, ex);
		} finally {
			try {
				ctx.close();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}

	public static <T> T locate(Class<T> type) {
		try {
			return find(getInitialContext(), type);
		} catch (NamingException e) {
			throw new RuntimeException("Couldn't locate Object with type "
					+ type.getName());
		}
	}

	@SuppressWarnings("unchecked")
	private static <T> T find(Context ctx, Class<T> ejbType)
			throws NamingException {
		NamingEnumeration ne = null;
		try {
			ne = ctx.list("");
			while (ne.hasMore()) {
				NameClassPair element = (NameClassPair) ne.next();
				try {
					Object value = ctx.lookup(element.getName());

					if (value != null) {
						if (ejbType.isAssignableFrom(value.getClass())) {
							return (T) value;
						} else if (value instanceof Context) {
							Context subctx = (Context) value;
							Object ejb = find(subctx, ejbType);
							if (ejb != null)
								return (T) ejb;
						}
					}
				} catch (Exception e) {
				}
			}
		} catch (NamingException e) {
		} finally {
			try {
				if (ne != null) {
					ne.close();
				}
			} catch (NamingException e) {
			}
		}
		return null;
	}

	public static void printTree(Log log) {
		log.debug("----------------------------------------------------------");
		log.debug("JNDI Tree");
		log.debug("----------------------------------------------------------");
		print(log, initialContext, "");
		log.debug("----------------------------------------------------------");
		try {
			print(log, (Context) getInitialContext().lookup("java:"), "");
		} catch (NamingException e) {
			throw new RuntimeException(e);
		}
		log.debug("----------------------------------------------------------");
	}

	public static void print(Log log, Context ctx, String tab) {
		NamingEnumeration e = null;
		try {
			e = ctx.list("");
			while (e.hasMore()) {
				NameClassPair element = (NameClassPair) e.next();
				log.debug(tab + element);
				Object value = ctx.lookup(element.getName());
				if (value instanceof Context) {
					Context subctx = (Context) value;
					print(log, subctx, tab + "--> ");
				}
			}
		} catch (NamingException e1) {
		} finally {
			try {
				if (e != null) {
					e.close();
				}
			} catch (NamingException e2) {
			}
		}
	}
}
